package io.primeval.reflex.arguments;

import java.lang.reflect.Parameter;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * This class represents the arguments passed to an intercepted method. When requested to, Aspecio will create an instance for each invocation, and possibly
 * allow an {@link Advice} to change them before an invocation.
 * </p>
 * <p>
 * {@link Arguments} generated by Aspecio do not box primitive types, and as such boxed and non-boxed types have to be managed separately.
 * </p>
 * <p>
 * {@link Arguments} generated by Aspecio are <b>immutable</b> and thus <b>thread-safe</b>. They implement {@link Object#equals(Object)} and
 * {@link Object#hashCode()} and thus can be used as keys for cache.
 * </p>
 */
public interface Arguments extends ArgumentsTrait {

    /**
     * Instance for parameter-less methods.
     */
    public static final Arguments EMPTY_ARGUMENTS = new Arguments() {

        public List<Parameter> parameters() {
            return Collections.emptyList();
        };

        public ArgumentsUpdater updater() {
            return ArgumentsUpdater.EMPTY_ARGUMENTS_UPDATER;
        };

        public <T> T objectArg(String argName) {
            throw new IllegalArgumentException("no argument");
        }

        public int intArg(String argName) {
            throw new IllegalArgumentException("no argument");
        };

        public short shortArg(String argName) {
            throw new IllegalArgumentException("no argument");
        };

        public long longArg(String argName) {
            throw new IllegalArgumentException("no argument");
        };

        public byte byteArg(String argName) {
            throw new IllegalArgumentException("no argument");
        };

        public boolean booleanArg(String argName) {
            throw new IllegalArgumentException("no argument");
        };

        public float floatArg(String argName) {
            throw new IllegalArgumentException("no argument");
        };

        public double doubleArg(String argName) {
            throw new IllegalArgumentException("no argument");
        };

        public char charArg(String argName) {
            throw new IllegalArgumentException("no argument");
        }
    };

    /**
     * Obtain an {@link ArgumentsUpdater} for this argument, to change the values of the different arguments and modify a method invocation before it happens.
     * 
     * @return the {@link ArgumentsUpdater} for this instance of {@link Arguments}.
     */
    ArgumentsUpdater updater();

    /**
     * Arguments generated by Aspecio implement {@link Object#equals(Object)} so that two Arguments of the same method, from the same class, and equal values
     * will be considered equal.
     * 
     * @param other
     *            The other object to compare with.
     * @return {@literal true} if this instance is equal with other, {@literal false} otherwise.
     */
    boolean equals(Object other);

    /**
     * Arguments generated by Aspecio implement {@link Object#hashCode()} so that two equal {@link Arguments} instance will share the same hashCode. The hash
     * definition follows the algorithm as described in item 8 in Effective Java by Josh Bloch.
     * 
     * @return this {@link Arguments}'s hashCode
     */
    int hashCode();
}